## Sid Meier's Civilization 4
## Copyright Firaxis Games 2005
##
## sdCultureConquest originally by Stone-D (Laga Mahesa)
## Copyright Laga Mahesa 2005
##
## Updated by TheLopez
## Version 1.30


from CvPythonExtensions import *
import CvUtil
import CvScreensInterface
import CvDebugTools
import PyHelpers
import Popup as PyPopup
import sys
import cPickle as pickle
import CvConfigParser

gc = CyGlobalContext()
CyGameInstance = gc.getGame()
localText = CyTranslator()
PyPlayer = PyHelpers.PyPlayer
PyInfo = PyHelpers.PyInfo


# Change the value to false if cities founded on city ruins should not be given 
# part of the culture from the city that created the city ruins.
# Default value is true
g_bCityRuinsGiveCulture = true

# Change the value to false if the culture given by city ruins should be the 
# same as the player who founded the city. If set to true then the culture 
# given to the new city will be from the civilization that last owned the city 
# that created the city ruins.
# Default value is true
g_bCityRuinsGiveOldCulture = true

# Increase or decrease the value to change the number of years that city ruins 
# give culture.
# Default value is 100
g_iMaxYearsCityRuinsGiveCulture = 100

# Increase or decrease the value to change the max amount of culture in percent
# city ruins give.
# Default value is 20
g_iMaxCultureCityRuinsGive = 20

# Change the value to false if the founder of a conquered city should not be 
# allowed to be reassigned if the conqueror is not the original founder and the 
# losing civilization is also not the original founder and the city's culture 
# is at least double what it was when the founder lost it.
# Default value is true
g_bAllowCityFounderReassignment = true

# Change the value to false if culture should be maintained after a city is 
# captured by a civilization from another civilization.
# Default value is true
g_bCityConquestRetainsCulture = true

# Increase or decrease the value to change the max amount of culture in percent
# retained after a city is conquered.
# Default value is 20
g_iMaxCultureRetained = 20

################# SD-UTILITY-PACK ###################
import sdToolKit
sdEcho         = sdToolKit.sdEcho
sdGetTimeInt   = sdToolKit.sdGetTimeInt
sdGameYearsInt = sdToolKit.sdGameYearsInt
sdModLoad      = sdToolKit.sdModLoad
sdModSave      = sdToolKit.sdModSave
sdEntityInit   = sdToolKit.sdEntityInit
sdEntityWipe   = sdToolKit.sdEntityWipe
sdEntityExists = sdToolKit.sdEntityExists
sdGetVal       = sdToolKit.sdGetVal
sdSetVal       = sdToolKit.sdSetVal

############### SD-CULTURE-CONQUEST #################

strModID        = 'EnhancedCultureConquestUtils'

NAME = "Name"
CAPTURE_COUNT = "Capture Count"
CAPTURE_STATE = "Capture State"
FOUNDER	= "Founder"
FCULTURE = "fCulture"
DATE_LOST = "Date Lost"
LOSER = "Loser"
OCULTURE = "oCulture"
CITY_RAZED = "City Razed"

def loadConfigurationData():
	global g_bCityRuinsGiveCulture
	global g_bCityRuinsGiveOldCulture
	global g_iMaxYearsCityRuinsGiveCulture
	global g_iMaxCultureCityRuinsGive
	global g_bAllowCityFounderReassignment
	global g_bCityConquestRetainsCulture
	global g_iMaxCultureRetained
	
	config = CvConfigParser.CvConfigParser("ViSa_v3.ini")

	if(config != None):
		g_bCityRuinsGiveCulture = config.getboolean("Cultural Influences", "City Ruins Give Culture", True)
		g_bCityRuinsGiveOldCulture = config.getboolean("Cultural Influences", "City Ruins Give Old Culture", True)
		g_iMaxYearsCityRuinsGiveCulture = config.getint("Cultural Influences", "Max Years City Ruins Give Culture", 100)
		g_iMaxCultureCityRuinsGive = config.getint("Cultural Influences", "Max Culture City Ruins Give", 20)
		g_bAllowCityFounderReassignment = config.getboolean("Cultural Influences", "Allow City Founder Reassignment", True)
		g_bCityConquestRetainsCulture = config.getboolean("Cultural Influences", "City Conquest Retains Culture", True)
		g_iMaxCultureRetained = config.getint("Cultural Influences", "Max Culture Retained", 20)

class EnhancedCultureConquestUtils:

	# Fixes the culture for the city passed in.
	def fixCityCulture(self, objCity):

		# Return immediately if an invalid city was pased in
		if(objCity == None):
			return
		
		# Return immediately if an invalid city was pased in
		if(objCity.isNone()):
			return 

		strCityID = self.getCityID(objCity)
		
		# Setup the city data if it wasn't previously setup.
		if(not sdEntityExists(strModID, strCityID)):
			self.setupCityData(objCity)

		# Return if the city passed in wasn't really captured.		
		if (sdGetVal(strModID, strCityID, CAPTURE_STATE) == 0):
			return

		CaptureCount    = sdGetVal(strModID, strCityID, CAPTURE_COUNT)
		founder         = sdGetVal(strModID, strCityID, FOUNDER)
		fCulture        = sdGetVal(strModID, strCityID, FCULTURE)
		fDateLost       = sdGetVal(strModID, strCityID, DATE_LOST)
		loser           = sdGetVal(strModID, strCityID, LOSER)
		oCulture        = sdGetVal(strModID, strCityID, OCULTURE)

		if (oCulture < 4):
			oCulture = 4
			
		cdice = CyRandom()
		cdice.init(oCulture)

		if ((loser != founder) and (oCulture > (fCulture*200)) and g_bAllowCityFounderReassignment and (objCity.getOwner() != founder)):
			founder = loser

		if ((loser == founder) or ((objCity.getOwner() == founder) and (oCulture > fCulture))):
			fCulture = oCulture
			fDateLost = sdGetTimeInt(gc.getGame().getGameTurn())

		nCulture = (oCulture/2) + cdice.get((oCulture/4), "Culture Conquest") + cdice.get((oCulture/4), "Culture Conquest")

		if (objCity.getOwner() == founder):
			yearMax         = sdGameYearsInt()
			yearNow         = sdGetTimeInt(gc.getGame().getGameTurn())
			yearDif         = yearNow - fDateLost
			Redux           = 1.0 - (yearDif/(yearMax * 0.25))
			
			Redux = max(0.0, Redux)
			
			iCulture = int(fCulture*Redux)
			
			nCulture = max(nCulture, iCulture)
		
		nCulture = int(float(nCulture)*(float(g_iMaxCultureRetained)/100.0))

		objCity.setCulture(objCity.getOwner(), nCulture, True)
		
		sdSetVal(strModID, strCityID, CAPTURE_COUNT, CaptureCount+1)
		sdSetVal(strModID, strCityID, CAPTURE_STATE, 0)
		sdSetVal(strModID, strCityID, FOUNDER, founder)
		sdSetVal(strModID, strCityID, FCULTURE, fCulture)
		sdSetVal(strModID, strCityID, DATE_LOST, fDateLost)


	# Called when a city is destroyed for whatever reason
	def handleCityRazed(self, objCity):

		# Return immediately if an invalid city was pased in
		if(objCity == None):
			return
		
		# Return immediately if an invalid city was pased in
		if(objCity.isNone()):
			return 
			
		# Get the city ID			
		strCityID = self.getCityID(objCity)
		
		# Setup the city data if it wasn't previously setup.
		if(not sdEntityExists(strModID, strCityID)):
			self.setupCityData(objCity)
							
		# Set the city as being razed
		sdSetVal(strModID, strCityID, CITY_RAZED, True)

		# Set the date the city was razed
		sdSetVal(strModID, strCityID, DATE_LOST, sdGetTimeInt(gc.getGame().getGameTurn()))

		# Set the last culture amount of the last loser of the city
		sdSetVal(strModID, strCityID, OCULTURE, objCity.getCulture(objCity.getOwner()))
		
		
	# Called when a city is conquered by a civ.
	def handleCityConquered(self, argsList):
		# Called at city acquired event.
		iLoser,playerType,objCity,bConquest,bTrade = argsList

		# Return immediately if the mod is configured to not carry culture from 
		# a captured city to their new owner
		if(not g_bCityConquestRetainsCulture):
			return
			
		# Return immediately if the city wasn't conquered
		if(not bConquest):
			return
			
		strCityID = self.getCityID(objCity)
		
		# Setup the city data if it wasn't previously setup.
		if(not sdEntityExists(strModID, strCityID)):
			self.setupCityData(objCity)
					
		# Set the city as being captured
		sdSetVal(strModID, strCityID, CAPTURE_STATE, 1)

		# Set the last loser of the city
		sdSetVal(strModID, strCityID, LOSER, iLoser)

		# Set the last culture amount of the last loser of the city
		sdSetVal(strModID, strCityID, OCULTURE, objCity.getCulture(iLoser))

		self.fixCityCulture(objCity)
		return
		

	# Called when a new city is built
	def handleCityBuilt(self, objCity):		

		# Return immediately if an invalid city was pased in
		if(objCity == None):
			return
		
		# Return immediately if an invalid city was pased in
		if(objCity.isNone()):
			return 
			
		# Get the city ID			
		strCityID = self.getCityID(objCity)
		
		iOldOwner = -1
		iOldCulture = -1
		iLostYear = -1
		bCityRazed = false
		iCurrentYear = sdGetTimeInt(gc.getGame().getGameTurn())
		
		# Setup the city data if it wasn't previously setup.
		if(sdEntityExists(strModID, strCityID)):
			iOldOwner = sdGetVal(strModID, strCityID, LOSER)
			iOldCulture = sdGetVal(strModID, strCityID, OCULTURE)
			iLostYear = sdGetVal(strModID, strCityID, DATE_LOST)
			bCityRazed = sdGetVal(strModID, strCityID, CITY_RAZED)

			# If the old city was razed then 
			if(bCityRazed and g_bCityRuinsGiveCulture):
				iMaxCulture = float(g_iMaxCultureCityRuinsGive)/100.0
				iNewCulture = int((iOldCulture * ((1+iCurrentYear - iLostYear) / (g_iMaxYearsCityRuinsGiveCulture * 0.15))) * iMaxCulture)
				iCultureOriginator = objCity.getOwner()
				
				if(g_bCityRuinsGiveOldCulture):
					iCultureOriginator = iOldOwner
									
				objCity.setCulture(iCultureOriginator, iNewCulture, true)
		
		# Setup the city data
		self.setupCityData(objCity, true)

		
	# Returns a city ID that can be used to uniquely identify a city. It will 
	# return None if an invalid city is passed in. Used for storing data using 
	# the SD-Toolkit.
	def getCityID(self, objCity):

		# Return None immediately if an invalid city was pased in
		if(objCity == None):
			return None
		
		# Return None immediately if an invalid city was pased in
		if(objCity.isNone()):
			return None
		
		# Get the plot the city is on
		objCityPlot = objCity.plot()
		
		# Construct the ID string
		strId = "%s-%s" %(objCityPlot.getX(), objCityPlot.getY())

		return strId
		
	
	# Sets up the city data in the game using the SD-Toolkit
	def setupCityData(self, objCity, bWipeExistingData=false):
	
		# Return immediately if an invalid city was pased in
		if(objCity == None):
			return
		
		# Return immediately if an invalid city was pased in
		if(objCity.isNone()):
			return 
			
		strCityId = self.getCityID(objCity)

		# Wipe out the existing data if we are asked to
		if(bWipeExistingData):
			sdEntityWipe(strModID, strCityId)	

		# Setup the city data structure
		vTable =	{
						NAME			: objCity.getName(),
						CAPTURE_COUNT	: 0,
						CAPTURE_STATE	: 0,
						FOUNDER			: objCity.getOwner(),
						FCULTURE		: 0,
						DATE_LOST		: sdGetTimeInt(gc.getGame().getGameTurn()),
						LOSER			: 0,
						OCULTURE		: 0,
						CITY_RAZED		: False,
					}

		sdEntityInit(strModID, strCityId, vTable)	